package com.qiangesoft.pdf.util;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import technology.tabula.*;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * pdf工具类
 * ps:适合解析纯文本、解析表格数据
 *
 * @author qiangesoft
 * @date 2025-05-28
 */
@Slf4j
public class PdfUtil {

    public static void main(String[] args) throws FileNotFoundException {
        // 解析文本形如：420000878324355\r\n437657\r\n2025-04-01\r\n12:47:32\r\n商户消费 支出 广州银行信\r\n用卡(0873)\r\n5.00 一点停 xxx\r\n0fseae
        String txt = readTxtFromPdf("C:\\Users\\admin\\Desktop\\微信流水.pdf", null);
        System.out.println(txt);

        // 解析数据形如：[[{k1=420000878324355437657, k2=2025-04-0112:47:32, k3=商户消费, k4=支出, k5=广州银行信用卡(0873), k6=5.00, k7=一点停, k8=xxx0fseae}]]
        List<List<Map<String, String>>> dataGroupList = readTableDataFromPdf("C:\\Users\\admin\\Desktop\\微信流水.pdf", null, true);
        for (List<Map<String, String>> list : dataGroupList) {
            for (Map<String, String> map : list) {
                System.out.println(JSON.toJSONString(map));
            }
        }
    }

    /**
     * 解析pdf的文本数据
     *
     * @param filePath 文件路径
     * @param password 文件密码
     * @return
     */
    public static String readTxtFromPdf(String filePath, String password) throws FileNotFoundException {
        return readTxtFromPdf(new FileInputStream(filePath), password);
    }

    /**
     * 解析pdf的文本数据
     *
     * @param inputStream 文件流
     * @param password 文件密码
     * @return
     */
    public static String readTxtFromPdf(InputStream inputStream, String password) {
        String textContent = "";
        try (PDDocument document = PDDocument.load(inputStream, password)) {
            PDFTextStripper stripper = new PDFTextStripper();
            textContent = stripper.getText(document);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return textContent;
    }

    /**
     * 解析pdf的表格数据
     *
     * @param filePath 文件路径
     * @param password 文件密码
     * @param skipFirstRow 是否跳过表头行 【连续分页表格可能每页有表头】
     * @return
     */
    public static List<List<Map<String, String>>> readTableDataFromPdf(String filePath, String password, boolean skipFirstRow) throws FileNotFoundException {
        return readTableDataFromPdf(new FileInputStream(filePath), password, skipFirstRow);
    }

    /**
     * 解析pdf的表格数据
     *
     * @param inputStream 文件流
     * @param password 文件密码
     * @param skipFirstRow 是否跳过表头行
     * @return
     */
    public static List<List<Map<String, String>>> readTableDataFromPdf(InputStream inputStream, String password, boolean skipFirstRow) {
        // 按照同一个表格分组
        List<List<Map<String, String>>> dataGroupList = new ArrayList<>();

        // 表格提取算法
        SpreadsheetExtractionAlgorithm algorithm = new SpreadsheetExtractionAlgorithm();

        try (PDDocument document = PDDocument.load(inputStream, password)) {
            ObjectExtractor extractor = new ObjectExtractor(document);
            PageIterator pi = extractor.extract();
            // 遍历页
            double x = 0;
            int tableIndex = 0;
            int tableHeadRowNum = 0;
            List<Table> tables = new ArrayList<>();
            List<String> fieldList = new ArrayList<>();
            while (pi.hasNext()) {
                Page page = pi.next();
                List<Table> tableList = algorithm.extract(page);

                // 遍历表格
                for (Table table : tableList) {
                    if (tableIndex == 0) {
                        tableHeadRowNum = getTableHeadRowNum(table, fieldList);
                        tables.add(table);
                        tableIndex++;
                    } else {
                        // 第一个 or x轴且列数相同为同一个表格
                        if (new BigDecimal(table.getX()).subtract(new BigDecimal(x)).abs().compareTo(new BigDecimal("0.001")) <= 0
                                && fieldList.size() == table.getRows().get(0).size()) {
                            tables.add(table);
                        } else {
                            List<Map<String, String>> dataList = convertTableToMap(tables, fieldList, tableHeadRowNum, skipFirstRow);
                            dataGroupList.add(dataList);

                            tables = new ArrayList<>();
                            tables.add(table);
                            tableIndex = 0;
                        }
                    }
                    x = table.getX();
                }
            }

            // 最后一个特殊处理
            if (!tables.isEmpty()) {
                List<Map<String, String>> dataList = convertTableToMap(tables, fieldList, tableHeadRowNum, skipFirstRow);
                dataGroupList.add(dataList);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return dataGroupList;
    }

    /**
     * 获取字段并返回表格头的行
     *
     * @param table 表格
     * @param fieldList 字段列表
     * @return
     */
    private static int getTableHeadRowNum(Table table, List<String> fieldList) {
        // 获取表格头
        int headRowNum = 0;
        List<List<RectangularTextContainer>> rowList = table.getRows();
        for (int i = 0; i < rowList.size(); i++) {
            fieldList.clear();
            List<RectangularTextContainer> cellList = rowList.get(i);
            int k = 0;
            for (int j = 0; j < cellList.size(); j++) {
                RectangularTextContainer cell = cellList.get(j);
                if (cell instanceof Cell) {
                    k++;
                    fieldList.add("k" + k);
                }
            }

            if (fieldList.size() == cellList.size()) {
                headRowNum = i;
                break;
            }
        }

        return headRowNum;
    }

    /**
     * 将表格数据转为映射数据
     *
     * @param tableList 表格列表
     * @param fieldList 字段列表
     * @param tableHeadRowNum 表格头行
     * @param skipFirstRow 是否跳过表头行
     * @return
     */
    private static List<Map<String, String>> convertTableToMap(List<Table> tableList, List<String> fieldList, int tableHeadRowNum, boolean skipFirstRow) {
        List<Map<String, String>> dataList = new ArrayList<>();

        for (int i = 0; i < tableList.size(); i++) {
            // 表格所有行
            Table table = tableList.get(i);
            List<List<RectangularTextContainer>> rowList = table.getRows();

            // 遍历行
            for (int j = (i == 0 ? tableHeadRowNum + 1 : skipFirstRow ? 1 : 0); j < rowList.size(); j++) {
                List<RectangularTextContainer> cellList = rowList.get(j);
                Map<String, String> data = new HashMap<>();
                // 遍历列
                for (int m = 0; m < cellList.size(); m++) {
                    RectangularTextContainer cell = cellList.get(m);
                    // 去除换行符后设置值
                    String text = cell.getText().replace("\r", "");
                    data.put(fieldList.get(m), text);
                }
                dataList.add(data);
            }
        }
        return dataList;
    }

    /**
     * 读取指定文字中间的文本
     *
     * @param txt 文本
     * @param startStr 开始字符串
     * @param endStr 结束字符串
     * @return
     */
    public static String readTxtFormTxt(String txt, String startStr, String endStr) {
        int index1 = txt.indexOf(startStr);
        if (index1 == -1) {
            return null;
        }
        int index2 = txt.length();
        if (endStr != null) {
            index2 = txt.indexOf(endStr);
            if (index2 == -1) {
                index2 = txt.length();
            }
        }

        return txt.substring(index1 + startStr.length(), index2);
    }

}
